
    /**用于同步集合中的每个元素对应的模型
     *@param val {Any} 集合中的某个元素，可以是一个VM，也可以是一个普通对象，或者说简单的数据类型，
     *@param i {Number} 元素对应的索引值
     **/

    function syncModel(val, i) {
        var type = getType(val)
        if (type === "array" || type === "object") {
            val = val.$id ? val : modelFactory(val, val, type === "array")
            this[i] = val.$model
        }
        return val
    }

    function Collection(list, model, prop) {
        var collection = list.map(syncModel, list) //转换里面的元素为VM
        collection.$id = generateID()
        collection[subscribers] = []
        collection.$model = collection.$json = list
        var dynamic = modelFactory({
            length: list.length
        })
        dynamic.$watch("length", function() {
            model && model.$fire(prop + ".length")
        })
        "push,pop,shift,unshift,splice".replace(rword, function(method) {
            collection[method] = function() {
                var len = this.length,
                        ret
                if (/push|unshift|splice/.test(method)) {
                    var margs = [].slice.call(arguments)

                    var vmargs = margs.map(syncModel, margs)

                    list[method].apply(list, arguments)
                    ret = list[method].apply(this, vmargs)
                    notifySubscribers(this, method, vmargs, len)

                } else {
                    list[method].call(this)
                    ret = list[method]()
                    notifySubscribers(this, method, arguments, len)
                }
                dynamic.length = list.length
                return ret
            }
        })
        "sort,reverse".replace(rword, function(method) {
            collection[method] = function() {
                list[method].apply(this, arguments)
                var neo = this.map(function(el) {
                    return el && el.$model ? el.$model : el
                })
                var n = list.length
                for (var i = 0; i < n; i++) {
                    var a = list[i],
                            b = neo[i]
                    if (a !== b) {
                        list.splice(i, 1)
                        list.push(a)
                        notifySubscribers(collection, "reroder", [i])
                        i = i - 1
                    }
                }
                return this
            }
        })
        collection.isCollection = true
        collection.clear = function() {
            this.length = dynamic.length = 0 //清空数组
            notifySubscribers(this, "clear", [])
            return this
        }
        collection.update = function(val) {
            Array.isArray(val) && updateViewModel(this, val, true)
            return this
        }
        collection.sortBy = function(fn, scope) { //按某属性排序
            this.update(avalon.Array.sortBy(list, fn, scope))
            return this
        }
        collection.contains = function(el) { //判定是否包含
            return this.indexOf(el) !== -1
        }
        collection.ensure = function(el) {
            if (!this.contains(el)) { //只有不存在才push
                this.push(el)
            }
            return this
        }
        collection.set = function(index, val) {
            if (index >= 0 && index < this.length) {
                if (/array|object/.test(getType(val))) {
                    model && model.$fire(prop + ".changed")
                    if (val.$model) {
                        val = val.$model
                    }
                    updateViewModel(this[index], val, Array.isArray(val))
                } else if (this[index] !== val) {
                    this[index] = val
                    model && model.$fire(prop + ".changed")
                    notifySubscribers(this, "set", arguments)
                }
            }
            return this
        }
        collection.size = function() { //取得数组长度，这个函数可以同步视图，length不能
            return dynamic.length
        }
        collection.remove = function(item) { //移除第一个等于给定值的元素
            var index = this.indexOf(item)
            return this.removeAt(index)
        }
        collection.removeAt = function(index) { //移除指定索引上的元素
            if (index >= 0 && (index % 1 === 0)) {
                list.splice(index, 1)
                this.splice(index, 1) //DOM操作非常重,因此只有非负整数才删除
                return this
            }
        }
        collection.removeAll = function(all) { //移除N个元素
            if (Array.isArray(all)) {
                all.forEach(function(el) {
                    collection.remove(el)
                })
            } else if (typeof all === "function") {
                for (var i = this.length - 1; i >= 0; i--) {
                    var el = this[i]
                    if (all(el, i)) {
                        this.splice(i, 1)
                    }
                }
            } else {
                this.clear()
            }
        }
        return collection
    }
    //////////////////////////// each binding  ////////////////////////
    //https://developer.mozilla.org/en-US/docs/DOM/range.deleteContents

    function emptyNode(parent) {
        while (parent.firstChild) {
            parent.removeChild(parent.firstChild)
        }
    }
    bindingHandlers["each"] = function(data, vmodels) {
        var parent = data.element
        var array = parseExpr(data.value, vmodels, data)
        var list
        if (typeof array == "object") {
            list = array[0].apply(array[0], array[1])
        }

        if (typeof list !== "object") {
            return list
        }
        var view = documentFragment.cloneNode(false)
        while (parent.firstChild) {
            view.appendChild(parent.firstChild)
        }
        data.view = view
        data.scopes = vmodels

        function updateListView(method, args, len) {
            var vmodels = updateListView.vmodels
            switch (method) {
                case "reroder":
                    var i = args[0]
                    var a = vmodels.splice(i, 1)
                    vmodels.push(a[0])
                    var frag = getItemView(parent, vmodels, i)
                    parent.appendChild(frag)
                    resetItemIndex(vmodels)
                    break
                case "set":
                    var model = vmodels[args[0]]
                    if (model) {
                        var n = model.$itemName
                        model[n] = args[1]
                    }
                    break
                case "push":
                    //在后面添加
                    forEach(args, function(index, item) {
                        addItemView(len + index, item, list, data, vmodels)
                    })
                    break
                case "unshift":
                    //在前面添加
                    resetItemIndex(vmodels, 0, list.length - len)
                    list.place = parent.firstChild
                    forEach(args, function(index, item) {
                        addItemView(index, item, list, data, vmodels)
                    })
                    list.place = null
                    break
                case "pop":
                    //去掉最后一个
                    var node = getItemView(parent, vmodels, vmodels.length - 1)
                    if (node) {
                        vmodels.pop()
                    }
                    break
                case "shift":
                    //去掉前面一个
                    var node = getItemView(parent, vmodels, 0)
                    if (node) {
                        vmodels.shift()
                        resetItemIndex(vmodels)
                    }
                    break
                case "splice":
                    var start = args[0],
                            second = args[1],
                            adds = [].slice.call(args, 2)
                    var deleteCount = second >= 0 ? second : len - start
                    if (deleteCount) { //连续删除几个
                        var node = getItemView(parent, vmodels, start, deleteCount)
                        if (node) {
                            vmodels.splice(start, deleteCount)
                            resetItemIndex(vmodels, start, start)
                        }
                    }
                    if (adds.length) { //连续添加几个
                        list.place = getIndexItem(parent, vmodels, start)
                        updateListView("push", adds, start)
                        resetItemIndex(vmodels, start, start)
                        list.place = null
                    }
                    break
                case "clear":
                    vmodels.length = 0
                    emptyNode(parent)
                    break
            }
        }
        updateListView.vmodels = []
        if ((list || {}).isCollection) {
            list[subscribers].push(updateListView)
        }
        updateListView("push", list, 0)
    }

    //取得目标子视图的第一个节点

    function getIndexItem(parent, vmodels, index) {
        var nodes = parent.childNodes
        var length = vmodels.length
        var group = nodes.length / length
        var node = nodes[group * index]
        return node
    }
    //将目标子视图的所有元素转换为一个文档碎片返回

    function getItemView(parent, vmodels, index, number) {
        var nodes = parent.childNodes
        var length = vmodels.length
        var group = nodes.length / length
        var node = nodes[group * index]
        var view = vmodels[index].$view
        var array = [node]
        number = number || 1
        length = group * number
        for (var i = 1; i < length; i++) {
            node = node.nextSibling
            array.push(node)
        }
        for (var i = 0, node; node = array[i++]; ) {
            view.appendChild(node)
        }
        return view
    }


    function resetItemIndex(vmodels, pos, add) { //重置路标
        pos = pos || 0
        add = add || 0
        for (var el; el = vmodels[pos++]; ) {
            el.$index = add++
        }
    }


    function addItemView(index, item, list, data, items) {
        var vmodels = data.scopes
        var parent = data.element
        var vmodel = createItemModel(index, item, list, data.args)
        var view = data.view.cloneNode(true)
        vmodels = [vmodel].concat(vmodels)
        items.splice(index, 0, vmodel)
        vmodel.$view = view
        if (!parent.inprocess) {
            parent.inprocess = 1 //locked!
            var hidden = parent.hidden //http://html5accessibility.com/
            parent.hidden = true //作用类似于display:none
        }
        scanNodes(view, vmodels, function() {
            parent.insertBefore(view, list.place || null)
        });
        if (parent.inprocess) {
            parent.hidden = hidden
            parent.inprocess = 0
        }
    }

    //为子视图创建一个ViewModel

    function createItemModel(index, item, list, args) {
        var itemName = args[0] || "$data"
        var source = {}
        source.$index = index
        source.$view = {}
        source.$itemName = itemName
        source[itemName] = {
            get: function() {
                return item
            },
            set: function(val) {
                item = val
            }
        }
        source.$first = {
            get: function() {
                return this.$index === 0
            }
        }
        source.$last = {
            get: function() { //有时用户是传个普通数组
                return this.$index === list.length - 1
            }
        }
        source.$remove = function() {
            return list.remove(item)
        }
        return modelFactory(source)
    }


    